package com.cuixichang.minimalism.domain;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.cuixichang.minimalism.acl.PlugDesign;
import com.cuixichang.minimalism.acl.PlugDesignComponent;
import com.cuixichang.minimalism.acl.SubassemblyDesignAbs;
import com.cuixichang.minimalism.basal.base.Validate;
import com.cuixichang.minimalism.basal.enums.DefaultNumberEnum;
import com.cuixichang.minimalism.basal.enums.SubassemblyTypeEnum;
import com.cuixichang.minimalism.core.security.userdetails.CredentialDetail;
import com.cuixichang.minimalism.service.IFormPlugService;
import com.cuixichang.minimalism.service.IFormService;
import com.cuixichang.minimalism.service.IFormValueService;
import com.cuixichang.minimalism.transfer.dto.IFormDTO;
import com.cuixichang.minimalism.transfer.dto.IFormPlugDTO;
import com.cuixichang.minimalism.transfer.dto.IFormValueDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class IFormValueCommandServiceImpl implements IFormValueCommandService{
    @Autowired
    private IFormService iFormService;
    @Autowired
    private IFormPlugService iFormPlugService;
    @Autowired
    private IFormValueService formValueService;
    @Autowired
    private List<SubassemblyDesignAbs> subassemblyDesigns;
    @Override
    public String getValue(String systemCode, String moduleName, String plugName, String groupId) {
        SubassemblyDesignAbs subassemblyDesign = subassemblyDesigns.stream().filter(designAbs -> {
            List<PlugDesign> plugs = PlugDesignComponent.getPlugDesign(designAbs.getType());
            if (CollectionUtils.isEmpty(plugs)) {
                return false;
            } else {
                Optional<PlugDesign> first = plugs.stream().filter(design -> plugName.equals(design.plugName())).findFirst();
                if(first.isPresent()){
                    PlugDesign design = first.get();
                    return !design.hidden();
                }else {
                    return false;
                }
            }
        }).findFirst().orElse(null);
        if(Objects.isNull(subassemblyDesign)) return StrUtil.EMPTY;
        List<IFormPlugDTO> fields = iFormPlugService.selectList(IFormPlugDTO.builder().createSystemCode(systemCode).moduleName(moduleName)
                .fieldType(subassemblyDesign.getType().getKey()).build());
        if(CollectionUtils.isEmpty(fields)) return StrUtil.EMPTY;
        List<Long> formIds = fields.stream().map(IFormPlugDTO::getFormId).distinct().collect(Collectors.toList());
        List<IFormDTO> fieldConfig = iFormService.selectByIds(formIds);
        if(CollectionUtils.isEmpty(fieldConfig)) return StrUtil.EMPTY;
        Map<Long, String> fieldLimitValue = fieldConfig.stream().collect(Collectors.toMap(IFormDTO::getId, IFormDTO::getLimitValue));
        List<IFormValueDTO> values = formValueService.selectList(IFormValueDTO.builder().createSystemCode(systemCode)
                .moduleName(moduleName).groupId(groupId).build(), (po, formValueQueryWrapper) -> {
            formValueQueryWrapper.in("form_id", fieldLimitValue.keySet());
        });
        if(CollectionUtils.isEmpty(values)) return StrUtil.EMPTY;
        return values.stream().map(IFormValueDTO::getFormValue).collect(Collectors.joining(StrUtil.COMMA));
    }

    @Override
    public Map<String, Object> getFormValue(String systemCode, String moduleName, String groupId) {
        return getFormValue(systemCode, moduleName,groupId, false);
    }

    @Override
    public Map<String, Object> getFormPreviewValue(String systemCode, String moduleName, String groupId) {
         return getFormValue(systemCode, moduleName,groupId, true);
    }

    @Override
    public Map<String, String> setFormValue(String systemCode, String moduleName, String groupId, Map<String, Object> formValue, CredentialDetail credentialDetail) {
        Assert.hasText(systemCode, "系统编码不能为空");
        Assert.hasText(moduleName, "模块名称不能为空");
        Assert.hasText(groupId, "分组ID不能为空");
        Map<String,String> result = Collections.EMPTY_MAP;
        List<IFormDTO> storeFields = iFormService.selectList(IFormDTO.builder().createSystemCode(systemCode)
                .moduleName(moduleName).build());
        if(CollectionUtils.isEmpty(storeFields)) return result;
        Map<String, SubassemblyDesignAbs> storeFieldMap = subassemblyDesigns.stream().collect(Collectors.toMap(
                subassemblyDesign -> subassemblyDesign.getType().getKey(), Function.identity()));
        result = storeFields.stream().filter(field -> {
            Long id = field.getId();
            IFormValueDTO historyValue = formValueService.selectOne(IFormValueDTO.builder().createSystemCode(systemCode)
                    .moduleName(moduleName).groupId(groupId).formId(id).build());
            String fieldType = field.getFieldType();
            SubassemblyDesignAbs subassemblyDesignAbs = storeFieldMap.get(fieldType);
            Assert.notNull(subassemblyDesignAbs, "不支持该类型字段");
            boolean hidden = isHidden(systemCode, moduleName, field.getId(), subassemblyDesignAbs.getType());
            Object uploadValue = formValue.get(String.valueOf(id));
            String value = subassemblyDesignAbs.resultValue(uploadValue);
            if(StrUtil.isBlank(value)){
                if(Objects.nonNull(historyValue)){
                    if(hidden){
                       return false;
                    }else {
                       formValueService.deleteById(historyValue.getId());
                    }
                }
                Boolean allowEmpty = field.getAllowEmpty();
                Assert.isTrue(allowEmpty, field.getFieldName()+"字段不允许为空");
            }
            Validate validate = subassemblyDesignAbs.valueValidate(field.getLimitValue(), value);
            if(Objects.nonNull(validate)){
                Assert.isTrue(validate.getChecked(), validate.getMessage());
            }
            if(Objects.nonNull(historyValue)){
                if(!hidden){
                    historyValue.setFormValue(value);
                    historyValue.setCreateLoginId(Objects.nonNull(credentialDetail)?credentialDetail.getLoginId(): DefaultNumberEnum.Zero.getCode());
                    formValueService.updateById(historyValue);
                }
            }else {
                IFormValueDTO insertValue = IFormValueDTO.builder().formId(id).moduleName(moduleName).groupId(groupId).formValue(value)
                   .createSystemCode(systemCode).createLoginId(Objects.nonNull(credentialDetail)?credentialDetail.getLoginId(): DefaultNumberEnum.Zero.getCode()).build();
                formValueService.insert(insertValue);
            }
            return !hidden;
        }).collect(Collectors.toMap(field->String.valueOf(field.getId()), field -> {
            String fieldType = field.getFieldType();
            SubassemblyDesignAbs subassemblyDesignAbs = storeFieldMap.get(fieldType);
            Object o = formValue.get(String.valueOf(field.getId()));
            return subassemblyDesignAbs.previewValue(field.getLimitValue(), subassemblyDesignAbs.resultValue(o));
        }));
        return result;
    }

    private boolean isHidden(String systemCode, String moduleName, Long formId, SubassemblyTypeEnum type){
            // 获取所有插件配置
            List<PlugDesign> plugDesign = PlugDesignComponent.getPlugDesign(type);
            // 查询已绑定的插件
            List<IFormPlugDTO> formPlug = iFormPlugService.selectList(IFormPlugDTO.builder().createSystemCode(systemCode)
                        .moduleName(moduleName).fieldType(type.getKey()).formId(formId).build());
            List<String> checkPlugs = CollectionUtils.isEmpty(formPlug)?Collections.emptyList():
                    formPlug.stream().map(IFormPlugDTO::getPlugName).collect(Collectors.toList());
            boolean hidden = false;
            if(!CollectionUtils.isEmpty(plugDesign) && !CollectionUtils.isEmpty(checkPlugs)){
                 hidden = CollectionUtils.containsAny(checkPlugs, plugDesign.stream().filter(PlugDesign::hidden).map(PlugDesign::plugName)
                            .collect(Collectors.toList()));
            }
            return hidden;
    }

        private Map<String, Object> getFormValue(String systemCode, String moduleName, String groupId, boolean isPreview) {
        if(StrUtil.isAllBlank(systemCode, moduleName,groupId)) return Collections.EMPTY_MAP;
        List<IFormValueDTO> stores = formValueService.selectList(IFormValueDTO.builder().createSystemCode(systemCode).moduleName(moduleName)
                .groupId(groupId).build());
        if(CollectionUtils.isEmpty(stores))  return Collections.EMPTY_MAP;
        Map<String, SubassemblyDesignAbs> storeFieldMap = subassemblyDesigns.stream().collect(Collectors.toMap(
                subassemblyDesign -> subassemblyDesign.getType().getKey(), Function.identity()));
        List<Long> formIds = stores.stream().map(IFormValueDTO::getFormId).distinct().collect(Collectors.toList());
        List<IFormDTO> fieldObjs = iFormService.selectByIds(formIds);
        if(CollectionUtils.isEmpty(fieldObjs)) return Collections.EMPTY_MAP;
        Map<Long, IFormDTO> fieldMap = fieldObjs.stream().collect(Collectors.toMap(IFormDTO::getId, Function.identity()));
        return stores.stream().filter(value -> {
            Long formId = value.getFormId();
            IFormDTO singleFiled = fieldMap.get(formId);
            if (Objects.nonNull(singleFiled)) {
                SubassemblyDesignAbs subassemblyDesignAbs = storeFieldMap.get(singleFiled.getFieldType());
                Assert.notNull(subassemblyDesignAbs, "不支持该类型字段");
                return !isHidden(systemCode, moduleName, formId, subassemblyDesignAbs.getType());
            }
            return false;
        }).collect(Collectors.toMap(value -> String.valueOf(value.getFormId()), value -> {
            Long formId = value.getFormId();
            IFormDTO singleFiled = fieldMap.get(formId);
            Object result;
            SubassemblyDesignAbs subassemblyDesignAbs = storeFieldMap.get(singleFiled.getFieldType());
            if(isPreview){
                result = subassemblyDesignAbs.previewValue(singleFiled.getLimitValue(), value.getFormValue());
            }else {
                result = subassemblyDesignAbs.resultValue(value.getFormValue());
            }
            return result;
        }));
    }
}
